#include "EstrategiaRecursoEscrituraDirecta.h"
#include "RecursoAlmacenamiento.h"

namespace Toolkit
{

EstrategiaRecursoEscrituraDirecta::EstrategiaRecursoEscrituraDirecta(
        const TipoSerializacion tserializacion,
        const unsigned long int &tamanoBloque, const bool &controlarUnicidad) :
    EstrategiaRecurso(tserializacion, tamanoBloque, controlarUnicidad)
{
}

EstrategiaRecursoEscrituraDirecta::~EstrategiaRecursoEscrituraDirecta()
{
}

void EstrategiaRecursoEscrituraDirecta::guardarDato(const Dato &dato,
        const Clave &clave)
{
    WrapperComponente wrapper;

    unsigned long int posicion;

    //primero chequeo unicidad
    if (getControlUnicidad())
    {
        bool encontrado = false;
        Dato *datoAux = dato.clonar();

        encontrado = getRecurso()->estrategiaAlmacenamiento-> //busco en secundario
                busquedaSecuencial(*getRecurso()->secundario, *datoAux, clave,
                        posicion, wrapper);
        if (!encontrado)
        {
            encontrado = buscarEnPrimario(clave, *datoAux, wrapper); //busco en primario
        }

        delete datoAux;

        if (encontrado)
        {
            throw ClaveDuplicadaException();
        }
    }

    //si no lo encuentra guardo en los dos y actualizo indice
    getRecurso()->estrategiaAlmacenamiento-> guardarDato(
            *getRecurso()->secundario, dato, clave, wrapper);

    posicion = getRecurso()->estrategiaAlmacenamiento-> guardarDato(
            *getRecurso()->primario, dato, clave, wrapper);

    if (getRecurso()->indice != NULL)
    {
        getRecurso()->indice->insertar(clave, posicion);
    }

}

bool EstrategiaRecursoEscrituraDirecta::recuperarDato(const Clave &clave,
        Dato &dato)
{
    WrapperComponente wrapper;

    unsigned long int posicion;
    bool encontrado = getRecurso()->estrategiaAlmacenamiento-> //busco en secundario
            busquedaSecuencial(*getRecurso()->secundario, dato, clave,
                    posicion, wrapper);

    if (!encontrado)
    {
        encontrado = buscarEnPrimario(clave, dato, wrapper);
        if (encontrado)
        {
            getRecurso()->estrategiaAlmacenamiento-> guardarDato(
                    *getRecurso()->secundario, dato, clave, wrapper);
        }
    }

    return encontrado;
}

void EstrategiaRecursoEscrituraDirecta::eliminarDato(const Clave &clave,
        Dato &dato)
{
    WrapperComponente wrapper;

    unsigned long int posicion;

    bool encontrado = getRecurso()->estrategiaAlmacenamiento-> //busco en secundario
            busquedaSecuencial(*getRecurso()->secundario, dato, clave,
                    posicion, wrapper);

    if (encontrado)
    {
        getRecurso()->estrategiaAlmacenamiento->eliminarDato(
                *getRecurso()->secundario, posicion, dato, clave, wrapper);
    }

    encontrado = buscarEnPrimario(clave, dato, wrapper, posicion);

    if (encontrado)
    {
        getRecurso()->estrategiaAlmacenamiento->eliminarDato(
                *getRecurso()->primario, posicion, dato, clave, wrapper);

        if (getRecurso()->indice != NULL)
        {
            getRecurso()->indice->eliminar(clave);
        }
    }

}

void EstrategiaRecursoEscrituraDirecta::actualizarDato(const Dato &dato,
        const Clave &clave)
{
    WrapperComponente wrapper;

    unsigned long int posicion;
    Dato *datoAux = dato.clonar();

    bool encontrado = getRecurso()->estrategiaAlmacenamiento-> //busco en secundario
            busquedaSecuencial(*getRecurso()->secundario, *datoAux, clave,
                    posicion, wrapper);
    try
    {
        if (encontrado)
        {
            getRecurso()->estrategiaAlmacenamiento->modificarDato(
                    *getRecurso()->secundario, dato, clave, posicion, wrapper);
        }
        else
        {
            getRecurso()->estrategiaAlmacenamiento-> guardarDato(
                    *getRecurso()->secundario, dato, clave, wrapper);
        }

        encontrado = buscarEnPrimario(clave, *datoAux, wrapper, posicion);
        if (encontrado)
        {
            unsigned long int nuevaPos =
                    getRecurso()->estrategiaAlmacenamiento->modificarDato(
                            *getRecurso()->primario, dato, clave, posicion,
                            wrapper);

            if (nuevaPos != posicion && getRecurso()->indice != NULL)
            {
                getRecurso()->indice->eliminar(clave);
                getRecurso()->indice->insertar(clave, nuevaPos);
            }
        }
        else
        {
            posicion = getRecurso()->estrategiaAlmacenamiento-> guardarDato(
                    *getRecurso()->primario, dato, clave, wrapper);

            if (getRecurso()->indice != NULL)
            {
                getRecurso()->indice->insertar(clave, posicion);
            }
        }
    } catch (DesbordeDeDatoException &e)
    {
        delete datoAux;
        throw e;
    }

    delete datoAux;
}

}
